using System.Drawing;
using System.Drawing.Imaging;
using Tesseract;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MedicalReportAssistant.Services
{
    public class TesseractOCRService : IOCRService, IDisposable
    {
        private readonly TesseractEngine _engine;
        private readonly ILogger<TesseractOCRService> _logger;
        private readonly IConfiguration _configuration;
        private bool _disposed;

        public TesseractOCRService(ILogger<TesseractOCRService> logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
            
            try
            {
                var tessdataPath = _configuration["OCR:TesseractDataPath"] ?? @"./tessdata";
                var language = _configuration["OCR:Language"] ?? "chi_sim+eng";
                var tessdataFullPath = Path.GetFullPath(tessdataPath);
                _logger.LogInformation("Tesseract引擎正在初始化，tessdata路径: {TessDataPath}", tessdataFullPath);

                // 检查tessdata目录和chi_sim.traineddata
                if (!Directory.Exists(tessdataFullPath))
                {
                    var msg = $"tessdata目录不存在: {tessdataFullPath}";
                    _logger.LogError(msg);
                    throw new DirectoryNotFoundException(msg);
                }
                var chiSimPath = Path.Combine(tessdataFullPath, "chi_sim.traineddata");
                if (!File.Exists(chiSimPath))
                {
                    var msg = $"缺少中文语言包chi_sim.traineddata: {chiSimPath}";
                    _logger.LogError(msg);
                    throw new FileNotFoundException(msg);
                }
                var engPath = Path.Combine(tessdataFullPath, "eng.traineddata");
                if (!File.Exists(engPath))
                {
                    var msg = $"缺少英文语言包eng.traineddata: {engPath}";
                    _logger.LogWarning(msg);
                }
                // 输出tessdata目录下所有文件
                var files = Directory.GetFiles(tessdataFullPath);
                _logger.LogInformation("tessdata目录下文件: {Files}", string.Join(", ", files));

                // 优化引擎配置
                _engine = new TesseractEngine(tessdataPath, language, EngineMode.LstmOnly);
                _engine.DefaultPageSegMode = PageSegMode.Auto;
                // _engine.SetVariable("tessedit_char_whitelist", whitelist); // 暂时禁用白名单以进行调试
                
                _logger.LogInformation("Tesseract引擎初始化成功，语言包: {Language}, 引擎模式: {EngineMode}", language, EngineMode.LstmOnly);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Tesseract引擎初始化失败");
                throw new InvalidOperationException("Tesseract引擎初始化失败，请检查安装和配置", ex);
            }
        }

        public async Task<string> RecognizeTextAsync(Bitmap image)
        {
            ArgumentNullException.ThrowIfNull(image);

            // 图像预处理：灰度化+二值化
            using var preprocessed = PreprocessImage(image);

            return await Task.Run(() =>
            {
                try
                {
                    using var pix = ConvertBitmapToPix(preprocessed);
                    using var page = _engine.Process(pix);
                    var text = page.GetText();
                    _logger.LogInformation("OCR识别完成，文本长度: {Length}", text.Length);
                    return text;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "OCR识别失败");
                    throw;
                }
            });
        }

        /// <summary>
        /// 图像预处理：灰度化+二值化
        /// </summary>
        private static Bitmap PreprocessImage(Bitmap src)
        {
            // 灰度化
            var gray = new Bitmap(src.Width, src.Height);
            using (var g = Graphics.FromImage(gray))
            {
                var colorMatrix = new System.Drawing.Imaging.ColorMatrix(
                    new float[][]
                    {
                        new float[] {0.299f, 0.299f, 0.299f, 0, 0},
                        new float[] {0.587f, 0.587f, 0.587f, 0, 0},
                        new float[] {0.114f, 0.114f, 0.114f, 0, 0},
                        new float[] {0,      0,      0,      1, 0},
                        new float[] {0,      0,      0,      0, 1}
                    });
                var attributes = new ImageAttributes();
                attributes.SetColorMatrix(colorMatrix);
                g.DrawImage(src, new Rectangle(0, 0, src.Width, src.Height), 0, 0, src.Width, src.Height, GraphicsUnit.Pixel, attributes);
            }
            // 二值化
            var threshold = 180; // 可根据实际情况调整
            for (int y = 0; y < gray.Height; y++)
            {
                for (int x = 0; x < gray.Width; x++)
                {
                    var pixel = gray.GetPixel(x, y);
                    var value = pixel.R;
                    var color = value > threshold ? Color.White : Color.Black;
                    gray.SetPixel(x, y, color);
                }
            }
            return gray;
        }

        public async Task<string> RecognizeTextFromScreenAsync(Rectangle region)
        {
            using var bitmap = CaptureScreenRegion(region);
            return await RecognizeTextAsync(bitmap);
        }

        public async Task<string> RecognizeTextFromFileAsync(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            using var bitmap = new Bitmap(filePath);
            return await RecognizeTextAsync(bitmap);
        }

        private static Bitmap CaptureScreenRegion(Rectangle region)
        {
            var bitmap = new Bitmap(region.Width, region.Height);
            using var graphics = Graphics.FromImage(bitmap);
            graphics.CopyFromScreen(region.Left, region.Top, 0, 0, region.Size);
            return bitmap;
        }

        private static Pix ConvertBitmapToPix(Bitmap bitmap)
        {
            using var ms = new MemoryStream();
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            ms.Position = 0;
            return Pix.LoadFromMemory(ms.ToArray());
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
            {
                _engine?.Dispose();
                _disposed = true;
            }
        }
    }
} 